/*
 * Copyright 2010 Okan Kahraman
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package tr.org.tx.vmot.ui.calendar;

import java.text.DateFormatSymbols;
import java.util.Calendar;
import java.util.GregorianCalendar;

import tr.org.tx.vmot.ui.base.AbstractView;

import com.vaadin.event.LayoutEvents.LayoutClickEvent;
import com.vaadin.event.LayoutEvents.LayoutClickListener;
import com.vaadin.ui.Alignment;
import com.vaadin.ui.Component;
import com.vaadin.ui.GridLayout;
import com.vaadin.ui.Label;

/**
 * @author Okan Kahraman
 *
 */
public class VmotCalendar extends AbstractView implements NavigableCalendar {
	
	private static final long serialVersionUID = -920791662161876L;
	
	private static final int calendarRows = 7;
	
	private static final int calendarCols = 7;
	
	private final GridLayout layout = new GridLayout(calendarCols,calendarRows);
	
	private Calendar calendar = GregorianCalendar.getInstance(getCurrentLocale());
	
	private DateFormatSymbols dateFormatSymbols = DateFormatSymbols.getInstance(getCurrentLocale());
	
	private static final int[] days = {Calendar.SUNDAY,Calendar.MONDAY,Calendar.TUESDAY,Calendar.WEDNESDAY,Calendar.THURSDAY,Calendar.FRIDAY,Calendar.SATURDAY};
	
	private int[] daysWithLocalizedOrder = new int[7];
	
	
	
	public VmotCalendar() {
		this(GregorianCalendar.getInstance().get(Calendar.MONTH),GregorianCalendar.getInstance().get(Calendar.YEAR));
	}
	
	public VmotCalendar(int month) {
		this(month,GregorianCalendar.getInstance().get(Calendar.YEAR));
	}
	
	public VmotCalendar(int month, int year) {
		calendar.set(Calendar.DATE, 1);
		calendar.set(Calendar.MONTH, month);
		calendar.set(Calendar.YEAR, year);
		populateDaysWithLocalizedOrder();
		setLayOutProperties();
		constructCalendar();
		addClickListenerToLayout();
		setCompositionRoot(layout);
	}

	@SuppressWarnings("serial")
	private void addClickListenerToLayout() {
		
		layout.addListener(new LayoutClickListener() {
	            public void layoutClick(LayoutClickEvent event) {
	            	
	            	if(event.isDoubleClick())
	            	{
		            	Component component = event.getChildComponent();
		            	//TODO find another solution instead of checking component style name
		            	if(component != null && "day".equals(component.getStyleName())) {
		            		Label clickedLabel = (Label)component;
		            		clickedLabel.setStyleName("dayMotivated");
		            	}
	            	}
	            		
	            }
	        });
	}

	private void setLayOutProperties() {
		layout.setSpacing(true);
	    layout.setMargin(true);
	    layout.setWidth("1000px");
	    layout.setHeight("600px");
	    layout.setStyleName("calendarBody");
	}

	private void constructCalendar() {
		constructCalendarHeader();
		constructCalendarBody(getCurrentMonth());
	}

	
	private void populateDaysWithLocalizedOrder() {
		//get the first day of week for th current locale (Sunday for USA, Monday for Turkey etc.)
		int current = calendar.getFirstDayOfWeek() - 1 ;
		for(int i=0; i < calendarCols; i++) {
			if(current == days.length)
				current=0;
			daysWithLocalizedOrder[i] = days[current];
			current++;
		}
	}
	
	private void constructCalendarHeader() {
		for(int i=0; i < calendarCols; i++) {
			Label headerLabel = newWeekDayHeaderLabel(daysWithLocalizedOrder[i]);
			layout.addComponent(headerLabel,i,0);
			layout.setComponentAlignment(headerLabel, Alignment.MIDDLE_CENTER);
		}
	}
	
	private Label newWeekDayHeaderLabel(int dayOfWeek) {
		Label label = new Label(dateFormatSymbols.getWeekdays()[dayOfWeek]);
		label.setStyleName("weekHeader");
		return label;
	}

	private int findColumnPositionOfDay(int day) {
		int columnPositionOfDay = 0;
		
		for(int i=0; i < calendarCols; i++) {
			if(daysWithLocalizedOrder[i] == day)
			columnPositionOfDay = i; 
		}
		
		return columnPositionOfDay;
	}
	
	
	private void constructCalendarBody(int month) {
		setCurrentMonth(month);
		int actualDayNumberInMonth = calendar.getActualMaximum(Calendar.DAY_OF_MONTH);
		calendar.set(Calendar.DATE, 1);
		int firstDayOfCurrentMonth = calendar.get(Calendar.DAY_OF_WEEK);
		int currentColumn=findColumnPositionOfDay(firstDayOfCurrentMonth);
		int currentRow = 1;
			
		for(int day=1; day <= actualDayNumberInMonth; day++) {
			Label label = newWeekDayLabel(day);
			layout.addComponent(label, currentColumn, currentRow);
			layout.setComponentAlignment(label, Alignment.MIDDLE_CENTER);
			currentColumn++;
			if(currentColumn % calendarCols == 0)  {
				currentColumn=0;
				currentRow++;
			}
		}
	}
	
	private void clearCalendarBody() {
		for(int row=1; row < calendarRows; row++)
			for(int col=0; col < calendarCols; col++)
				layout.removeComponent(col, row);	
	}

	private Label newWeekDayLabel(int dayOfMonth) {
		Label label = new Label(dayOfMonth + "");
		label.setStyleName("day");
		return label;
	}
	
	public int getCurrentMonth() {
		return calendar.get(Calendar.MONTH);
	}
	
	public void setCurrentMonth(int month) {
		calendar.set(Calendar.MONTH, month);
	}
	
	public int getCurrentYear() {
		return calendar.get(Calendar.YEAR);
	}
	
	public void setCurrentYear(int year) {
		calendar.set(Calendar.YEAR, year);
	}

	@Override
	public void previousMonth() {
		clearCalendarBody();
		calendar.add(Calendar.MONTH,-1);
		constructCalendarBody(getCurrentMonth());
	}

	@Override
	public void nextMonth() {
		clearCalendarBody();	
		calendar.add(Calendar.MONTH,1);
		constructCalendarBody(getCurrentMonth());
	}

	@Override
	public void navigateTo(int month, int year) {
		clearCalendarBody();
	}

	@Override
	public String getCurrentMonthName() {
		return dateFormatSymbols.getMonths()[getCurrentMonth()];
	}

}
